
#include <Liberty3D/Library/TaskScheduler.h>
#include <Liberty3D/Library/Task.h>

#include <dispatch/dispatch.h>
#include <unistd.h>
#include <pthread.h>

using namespace Liberty::Engine;
using namespace Liberty::Library;

static bool      initialized = false;
static pthread_t mainThread;
static dispatch_block_t mainThreadBlock;
static dispatch_block_t workerThreadBlock;

void TaskScheduler::consoleInit() {
    if (!initialized) {
        initialized = true;
        
        init();
        mainThread = pthread_self();
        
        mainThreadBlock = ^ {
            std::shared_ptr<Task> taskToRun(dequeue(true));
            
            if (taskToRun) {
                taskToRun->execute();
                finished(taskToRun);
            }
            else {
                // Queue back...
                dispatch_async(dispatch_get_main_queue(), mainThreadBlock);
            }
        };
    
        workerThreadBlock = ^ {
            if (!pooling()) {
                dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), workerThreadBlock);
            }
        };
    }
}

bool TaskScheduler::isMainThread() {
    return pthread_equal(mainThread, pthread_self())? true: false;
}

void TaskScheduler::scheduleImpl(const std::shared_ptr<Task>& task) {
    if (task->mustExecuteOnMainThread()) {
        dispatch_async(dispatch_get_main_queue(), mainThreadBlock);
    }
    else {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), workerThreadBlock);
    }
}

void TaskScheduler::cancelImpl(const std::shared_ptr<Task>& task) {
}

unsigned int TaskScheduler::numProcessors() {
    return (unsigned int)sysconf( _SC_NPROCESSORS_ONLN );
}

bool TaskScheduler::consoleLoop(bool autoStopWhenNoTask) {
    dispatch_main();
    return false;
}
